use core::ptr::NonNull;

use acpi::{AcpiHandler, AcpiTables, PciConfigRegions, PhysicalMapping};
use alloc::{alloc::Global, boxed::Box};
use spin::Mutex;

pub static ACPI_INFOS: Mutex<Option<AcpiInfos<'_>>> = Mutex::new(None);

pub struct AcpiInfos<'a> {
    pub pci_regions: PciConfigRegions<'a, Global>,
}

#[derive(Clone)]
struct AcpiUserMemHandler;

impl AcpiHandler for AcpiUserMemHandler {
    unsafe fn map_physical_region<T>(
        &self,
        physical_address: usize,
        size: usize,
    ) -> PhysicalMapping<Self, T> {
        let virtual_address = unsafe {
            let physical_address = physical_address;
            let virtual_address = physical_address;
            syscall::op::mmap(virtual_address, physical_address, size, 0x7);
            NonNull::new_unchecked(virtual_address as *mut T)
        };
        unsafe { PhysicalMapping::new(physical_address, virtual_address, size, size, self.clone()) }
    }

    fn unmap_physical_region<T>(_region: &PhysicalMapping<Self, T>) {}
}

pub fn init(rsdp_addr: usize) {
    let acpi_tables = unsafe {
        let tables = AcpiTables::from_rsdp(AcpiUserMemHandler, rsdp_addr);
        Box::leak(Box::new(tables.unwrap()))
    };

    let pci_regions = PciConfigRegions::new(acpi_tables).expect("Cannot get pci config regions");

    let infos = AcpiInfos { pci_regions };

    ACPI_INFOS.lock().replace(infos);
}
